package main

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Server struct {
	Ip   string
	Port int

	// 在线用户的列表,
	OnlineMap map[string]*User
	mapLock   sync.RWMutex

	// 消息广播的 channel,
	Message chan string
}

// 创建一个 server 的接口,
func NewServer(ip string, port int) *Server {
	server := &Server{Ip: ip,
		Port:      port,
		OnlineMap: make(map[string]*User),
		Message:   make(chan string),
	}
	return server
}

// 处理链接业务,
func (this *Server) Handler(conn net.Conn) {
	// 当前连接的业务,
	// fmt.Println("client connect success!")

	user := NewUser(conn, this)

	// 监听用户是否活跃的 channel,
	isLive := make(chan bool)

	// 用户上线,
	user.Online()

	// 接收客户端发送的消息,
	go func() {
		buf := make([]byte, 4096)
		for {
			n, err := conn.Read(buf)
			if n == 0 {
				// 用户下限,
				// 这里还有心跳超时, 然后 server 中 conn.Close() 调用到这里,
				user.Offline()
				return
			}
			if err != nil && err != io.EOF {
				fmt.Println("Conn read err:", err)
				return
			}

			// 提取用户的消息(去除 '\n' ), 将得到的消息进行广播,
			msg := string(buf[:n-1])
			user.DoMessage(msg)

			// 用户的任意消息, 代表当前用户是一个活跃的,
			isLive <- true
		}
	}()

	// 当前 handler 阻塞,
	for {
		select {
		case <-isLive:
			// 当前用户是活跃的, 应该重置定时器,
			// 这个分支不做任何事情, 就是为了更新 select, 更新下面的定时器,

		// case <-time.After(time.Second * 10):
		case <-time.After(time.Second * 300):
			// 已经超时, 将当前的 user 强制的关闭,
			user.SendMsg("timeout and kicked ...\n")
			// 销毁用户的资源,
			close(user.Chan)
			conn.Close()
			// 退出当前的 handler,
			return // 或者 runtime.Goexit(),
		}
	}

}

// 广播消息的方法,
func (this *Server) Broadcast(user *User, msg string) {
	sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
	this.Message <- sendMsg
}

// 监听 Message 广播 channel 的 goroutine, 一旦有消息就发送给全部的在线 user,,
func (this *Server) ListenMessage() {
	for {
		msg := <-this.Message

		// 将 msg 发送给全部的 User,
		this.mapLock.Lock()
		for _, cli := range this.OnlineMap {
			cli.Chan <- msg
		}
		this.mapLock.Unlock()
	}
}

// 启动服务器的方法,
func (this *Server) Start() {
	// socket listen
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port)) // "127.0.0.1:8888"
	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}

	// close listen_socket
	defer listener.Close()

	// 启动监听 Message 的 goroutine,
	go this.ListenMessage()

	for {
		// accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener accept err:", err)
			continue
		}

		// do_handler
		go this.Handler(conn)

	}
}

//
